package container_cmds

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"atomgit.com/openlinksaas/devc/utils"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/mount"
	"github.com/docker/docker/client"
	"github.com/docker/go-connections/nat"
	"github.com/spf13/cobra"
)

var createFlagImage string
var createFlagLocalPort int
var createFlagLocalPath string

var createCmd = &cobra.Command{
	Use: "create",
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 3 {
			return fmt.Errorf("need param [repoId] [repoPath] [serverPort]")
		}
		port, err := strconv.Atoi(args[2])
		if err != nil {
			return err
		}
		if port < 1024 || port >= 65535 {
			return fmt.Errorf("wrong serverPort must be 1-65534")
		}
		return nil
	},
	RunE: runCreate,
}

func runCreate(cmd *cobra.Command, args []string) error {
	repoId := args[0]
	repoPath := args[1]
	serverPortStr := args[2]

	cmdList := []string{} //TODO
	portMapList := []string{fmt.Sprintf("127.0.0.1:%s:%d", serverPortStr, createFlagLocalPort)}

	devCfgJson := []byte{}
	envList := []string{}

	cli, err := client.NewClientWithOpts(client.FromEnv)
	if err != nil {
		return err
	}
	if strings.Contains(createFlagImage, "code-server") {
		devCfg, err := LoadSimpleDevConfig(repoPath)
		if err != nil {
			return err
		}
		for _, pkgVer := range devCfg.PkgVersionList {
			cmdList = append(cmdList, fmt.Sprintf("%s@%s@%s", pkgVer.Package, pkgVer.Version, pkgVer.PluginAddr))
		}
		for _, forwardPort := range devCfg.ForwardPortList {
			hostIp := "127.0.0.1"
			if forwardPort.Public {
				hostIp = "0.0.0.0"
			}
			portMapList = append(portMapList, fmt.Sprintf("%s:%d:%d", hostIp, forwardPort.HostPort, forwardPort.ContainerPort))
		}

		devCfgJson, err = json.Marshal(devCfg)
		if err != nil {
			return err
		}

		for _, envItem := range devCfg.EnvList {
			if envItem.Key == "" || envItem.Value == "EXTENSION_LIST" {
				continue
			}
			envList = append(envList, fmt.Sprintf("%s=%s", envItem.Key, envItem.Value))
		}
		if len(devCfg.ExtensionList) > 0 {
			tmpList := []string{}
			for _, extItem := range devCfg.ExtensionList {
				tmpList = append(tmpList, extItem.Id)
			}
			envList = append(envList, fmt.Sprintf("EXTENSION_LIST=%s", strings.Join(tmpList, ";")))
		}
	} else {
		envList = append(envList, "DISABLE_AUTH=true")
	}

	portSet, portMap, err := nat.ParsePortSpecs(portMapList)
	if err != nil {
		return err
	}

	cfg := &container.Config{
		Cmd:   cmdList,
		Image: createFlagImage,
		Labels: map[string]string{
			"repoId":     repoId,
			"provider":   "linksaas",
			"repoPath":   repoPath,
			"serverPort": serverPortStr,
			"devCfg":     string(devCfgJson),
		},
		ExposedPorts: portSet,
		Env:          envList,
	}

	hostCfg := &container.HostConfig{
		Mounts: []mount.Mount{
			{
				Type:        mount.TypeBind,
				Source:      repoPath,
				Target:      createFlagLocalPath,
				Consistency: mount.ConsistencyCached,
			},
		},
		PortBindings: portMap,
	}

	resp, err := cli.ContainerCreate(cmd.Context(), cfg, hostCfg, nil, nil, "")
	if err != nil {
		return err
	}
	utils.PrintResult(resp.ID)
	return nil
}

func init() {
	createCmd.Flags().StringVar(&createFlagImage, "image", "", "set docker image")
	createCmd.Flags().IntVar(&createFlagLocalPort, "localPort", 8080, "docker local port")
	createCmd.Flags().StringVar(&createFlagLocalPath, "localPath", "/workspace", "set docker localPath")
}
